!! Copyright (C) 2009,2010,2011,2012  Marco Restelli
!!
!! This file is part of:
!!   FEMilaro -- Finite Element Method toolkit
!!
!! FEMilaro is free software; you can redistribute it and/or modify it
!! under the terms of the GNU General Public License as published by
!! the Free Software Foundation; either version 3 of the License, or
!! (at your option) any later version.
!!
!! FEMilaro is distributed in the hope that it will be useful, but
!! WITHOUT ANY WARRANTY; without even the implied warranty of
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
!! General Public License for more details.
!!
!! You should have received a copy of the GNU General Public License
!! along with FEMilaro; If not, see <http://www.gnu.org/licenses/>.
!!
!! author: Marco Restelli                   <marco.restelli@gmail.com>

module mod_umfpack
!General comments: dummy interface to UMFPACK: none of the
!included procedures should be ever called! This module
!should be used if UMFPACK is not available.
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------

 use mod_messages, only: &
   mod_messages_initialized, &
   error,   &
   warning, &
   info

!-----------------------------------------------------------------------
 
 implicit none

!-----------------------------------------------------------------------

! Module interface

 public :: &
   mod_umfpack_constructor, &
   mod_umfpack_destructor,  &
   mod_umfpack_initialized, &
   working_umfpack, &
   umfpack_control, &
   umfpack_prl,     &
   umfpack_info,    &
   umf_int,         &
   umf_dp,          &
   umf_void,        &
   umfpack_a,       &
   umfpack_at,      &
   umfpack_aat,     &
   umfpack_pt_l,    &
   umfpack_l,       &
   umfpack_lt_p,    &
   umfpack_lat_p,   &
   umfpack_lt,      &
   umfpack_lat,     &
   umfpack_u_qt,    &
   umfpack_u,       &
   umfpack_q_ut,    &
   umfpack_q_uat,   &
   umfpack_ut,      &
   umfpack_uat,     &
   umf4def,         &
   umf4pcon,        &
   umf4pinf,        &
   umf4sym,         &
   umf4num,         &
   umf4sol,         &
   umf4solr,        &
   umf4fsym,        &
   umf4fnum

 private

!-----------------------------------------------------------------------

! Module types and parameters

 logical, parameter :: working_umfpack = .false.

 ! The UMFPACK integer and real types are defined as the default types
 integer, parameter ::             &
   umf_int = kind(1)
 integer, parameter ::             &
   umf_dp = kind(1.0)

 integer, parameter ::             &
   umf_void_example = 1
 integer, parameter ::             &
   umf_void = kind(umf_void_example)

 ! public members
 integer(umf_int), parameter :: &
   umfpack_a     = 0,  &! Ax = b
   umfpack_at    = 1,  &! AHx = b
   umfpack_aat   = 2,  &! ATx = b
   umfpack_pt_l  = 3,  &! PTLx = b
   umfpack_l     = 4,  &! Lx = b
   umfpack_lt_p  = 5,  &! LHPx = b
   umfpack_lat_p = 6,  &! LTPx = b
   umfpack_lt    = 7,  &! LHx = b
   umfpack_lat   = 8,  &! LTx = b
   umfpack_u_qt  = 9,  &! UQTx = b
   umfpack_u     = 10, &! Ux = b
   umfpack_q_ut  = 11, &! QUHx = b
   umfpack_q_uat = 12, &! QUTx = b
   umfpack_ut    = 13, &! UHx = b
   umfpack_uat   = 14   ! UTx = b

 ! These parameters are taken from umfpack.h. Notice that different
 ! versions of UMFPACK may use different values for these parameteres,
 ! so one shoud check that this module is consistent with the system
 ! umfpack.h.
 integer(umf_int), parameter ::      &
   umfpack_control = 20, &
   umfpack_info = 90,    &
   umfpack_prl = 0 + 1     ! add 1 when going from C to FORTRAN indexes

! Module variables

 ! public members
 logical, protected ::               &
   mod_umfpack_initialized = .false.
 ! private members
 character(len=*), parameter :: &
   err_msg = 'This is just a stub and should never be called'

 character(len=*), parameter :: &
   this_mod_name = 'mod_umfpack'

!-----------------------------------------------------------------------

contains

!-----------------------------------------------------------------------

 subroutine mod_umfpack_constructor()
  character(len=*), parameter :: &
    this_sub_name = 'constructor'

   !Consistency checks ---------------------------
   if( (mod_messages_initialized.eqv..false.) ) then
     call error(this_sub_name,this_mod_name, &
                'Not all the required modules are initialized.')
   endif
   if(mod_umfpack_initialized.eqv..true.) then
     call warning(this_sub_name,this_mod_name, &
                  'Module is already initialized.')
   endif
   !----------------------------------------------

   mod_umfpack_initialized = .true.
 end subroutine mod_umfpack_constructor

!-----------------------------------------------------------------------
 
 subroutine mod_umfpack_destructor()
  character(len=*), parameter :: &
    this_sub_name = 'destructor'
   
   !Consistency checks ---------------------------
   if(mod_umfpack_initialized.eqv..false.) then
     call error(this_sub_name,this_mod_name, &
                'This module is not initialized.')
   endif
   !----------------------------------------------

   mod_umfpack_initialized = .false.
 end subroutine mod_umfpack_destructor

!-----------------------------------------------------------------------
 
 subroutine umf4def(control)
  real(umf_dp), intent(out) :: control(umfpack_control)
  character(len=*), parameter :: this_sub_name = 'umf4def'

   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4def
 
!-----------------------------------------------------------------------
 
 subroutine umf4pcon(control)
  real(umf_dp), intent(in) :: control(umfpack_control)
  character(len=*), parameter :: this_sub_name = 'umf4pcon'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4pcon
 
!-----------------------------------------------------------------------
 
 subroutine umf4sym(n_row,n_col,ap,ai,ax,symbolic,control,info)
  integer, intent(in) :: n_row
  integer, intent(in) :: n_col
  integer, intent(in) :: ap(*)
  integer, intent(in) :: ai(*)
  real(umf_dp), intent(in) :: ax(*)
  integer(umf_void), intent(out) :: symbolic
  real(umf_dp), intent(in) :: control(umfpack_control)
  real(umf_dp), intent(out) :: info(umfpack_info)
  character(len=*), parameter :: this_sub_name = 'umf4sym'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4sym
 
!-----------------------------------------------------------------------
 
 subroutine umf4num(ap,ai,ax,symbolic,numeric,control,info)
  integer, intent(in) :: ap(*)
  integer, intent(in) :: ai(*)
  real(umf_dp), intent(in) :: ax(*)
  integer(umf_void), intent(in) :: symbolic
  integer(umf_void), intent(out) :: numeric
  real(umf_dp), intent(in) :: control(umfpack_control)
  real(umf_dp), intent(out) :: info(umfpack_info)
  character(len=*), parameter :: this_sub_name = 'umf4num'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4num
 
!-----------------------------------------------------------------------
 
 subroutine umf4sol(sys,x,b,numeric,control,info)
  integer, intent(in) :: sys
  real(umf_dp), intent(out) :: x(*)
  real(umf_dp), intent(in) :: b(*)
  integer(umf_void), intent(in) :: numeric
  real(umf_dp), intent(inout) :: control(umfpack_control)
  real(umf_dp), intent(out) :: info(umfpack_info)
  character(len=*), parameter :: this_sub_name = 'umf4sol'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4sol
 
!-----------------------------------------------------------------------
 
 subroutine umf4fsym(symbolic)
  integer(umf_void), intent(inout) :: symbolic
  character(len=*), parameter :: this_sub_name = 'umf4fsym'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4fsym
 
!-----------------------------------------------------------------------
 
 subroutine umf4fnum(numeric)
  integer(umf_void), intent(inout) :: numeric
  character(len=*), parameter :: this_sub_name = 'umf4fnum'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4fnum
 
!-----------------------------------------------------------------------

 subroutine umf4solr(sys,ap,ai,ax,x,b,numeric,control,info)
  integer(umf_int), intent(in) :: sys
  integer(umf_int), intent(in) :: ap(*)
  integer(umf_int), intent(in) :: ai(*)
  real(umf_dp), intent(in) :: ax(*)
  real(umf_dp), intent(out) :: x(*)
  real(umf_dp), intent(in) :: b(*)
  integer(umf_void), intent(in) :: numeric
  real(umf_dp), intent(in) :: control(umfpack_control)
  real(umf_dp), intent(out) :: info(umfpack_info)
  character(len=*), parameter :: this_sub_name = 'umf4solr'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4solr
 
!-----------------------------------------------------------------------

 subroutine umf4pinf(control,info)
  real(umf_dp), intent(in) :: control(umfpack_control)
  real(umf_dp), intent(in) :: info(umfpack_info)
  character(len=*), parameter :: this_sub_name = 'umf4pinf'
 
   call error(this_sub_name,this_mod_name,err_msg)
 end subroutine umf4pinf
 
!-----------------------------------------------------------------------

end module mod_umfpack

